//! 集成测试工具
//! 
//! 提供集成测试的通用工具和辅助函数

use std::sync::Arc;
use std::collections::HashMap;
use data_gateway_kernel::{DataGatewayKernel, Query, QueryType};
use data_gateway_kernel::query::{QueryOptions, QueryContext};

/// 创建测试用的内核实例
pub async fn create_test_kernel() -> anyhow::Result<Arc<DataGatewayKernel>> {
    let kernel = Arc::new(DataGatewayKernel::new().await?);
    kernel.start().await?;
    Ok(kernel)
}

/// 创建测试查询
pub fn create_test_query(id: &str, query_type: QueryType, content: &str) -> Query {
    Query {
        id: id.to_string(),
        query_type,
        content: content.to_string(),
        parameters: HashMap::new(),
        options: QueryOptions::default(),
        context: QueryContext::default(),
    }
}

/// 创建SQL查询
pub fn create_sql_query(id: &str, sql: &str) -> Query {
    create_test_query(id, QueryType::Sql, sql)
}

/// 创建脚本查询
pub fn create_script_query(id: &str, script: &str) -> Query {
    create_test_query(id, QueryType::Script, script)
}

/// 创建GraphQL查询
pub fn create_graphql_query(id: &str, graphql: &str) -> Query {
    create_test_query(id, QueryType::GraphQL, graphql)
}

/// 测试辅助函数：等待一段时间
pub async fn wait_for(duration_ms: u64) {
    tokio::time::sleep(tokio::time::Duration::from_millis(duration_ms)).await;
}

/// 测试辅助函数：验证查询结果
pub fn assert_query_success(result: &data_gateway_kernel::QueryResult) {
    assert!(result.is_success(), "查询应该成功，但失败了: {:?}", result.error);
    if let Some(duration) = result.stats.duration_ms {
        assert!(duration >= 0, "执行时间应该大于等于0");
    }
}

/// 测试辅助函数：验证查询失败
pub fn assert_query_failure(result: &data_gateway_kernel::QueryResult) {
    assert!(matches!(result.status, data_gateway_kernel::query::QueryStatus::Failed),
            "查询应该失败，但成功了");
    assert!(result.error.is_some(), "失败的查询应该有错误信息");
}

/// 测试配置
pub struct TestConfig {
    pub timeout_ms: u64,
    pub max_retries: u32,
    pub enable_logging: bool,
}

impl Default for TestConfig {
    fn default() -> Self {
        Self {
            timeout_ms: 5000,
            max_retries: 3,
            enable_logging: false,
        }
    }
}

/// 测试环境设置
pub struct TestEnvironment {
    pub kernel: Arc<DataGatewayKernel>,
    pub config: TestConfig,
}

impl TestEnvironment {
    /// 创建新的测试环境
    pub async fn new() -> anyhow::Result<Self> {
        Self::with_config(TestConfig::default()).await
    }
    
    /// 使用指定配置创建测试环境
    pub async fn with_config(config: TestConfig) -> anyhow::Result<Self> {
        if config.enable_logging {
            tracing_subscriber::fmt::init();
        }
        
        let kernel = create_test_kernel().await?;
        
        Ok(Self { kernel, config })
    }
    
    /// 执行查询并验证成功
    pub async fn execute_query_success(&self, query: Query) -> anyhow::Result<data_gateway_kernel::QueryResult> {
        let result = self.kernel.handle_query(query).await?;
        assert_query_success(&result);
        Ok(result)
    }
    
    /// 执行查询并验证失败
    pub async fn execute_query_failure(&self, query: Query) -> anyhow::Result<data_gateway_kernel::QueryResult> {
        let result = self.kernel.handle_query(query).await?;
        assert_query_failure(&result);
        Ok(result)
    }
    
    /// 清理测试环境
    pub async fn cleanup(&self) -> anyhow::Result<()> {
        self.kernel.stop().await?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_create_test_kernel() {
        let kernel = create_test_kernel().await.unwrap();
        assert!(kernel.is_running().await);
        kernel.stop().await.unwrap();
    }

    #[tokio::test]
    async fn test_create_queries() {
        let sql_query = create_sql_query("test", "SELECT 1");
        assert_eq!(sql_query.query_type, QueryType::Sql);
        assert_eq!(sql_query.content, "SELECT 1");
        
        let script_query = create_script_query("test", "var x = 1;");
        assert_eq!(script_query.query_type, QueryType::Script);
        assert_eq!(script_query.content, "var x = 1;");
    }

    #[tokio::test]
    async fn test_environment() {
        let env = TestEnvironment::new().await.unwrap();
        assert!(env.kernel.is_running().await);
        env.cleanup().await.unwrap();
    }
}
